package com.pj.project.sys_user;

import cn.dev33.satoken.util.SaResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.pj.project.sys_client.SysClientMapper;
import com.pj.project.sys_dict.service.ISysDictDataService;
import com.pj.project.sys_points_history.PointListenVO;
import com.pj.project.sys_points_history.SysPointHistory;
import com.pj.project.sys_points_history.SysPointHistoryService;
import com.pj.project.wx.wx_card.WxCard;
import com.pj.project.wx.wx_card.WxCardService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.card.membercard.WxMpMemberCardUpdateMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.pj.project.sys_user_password.SysUserPasswordService;
import com.pj.project4sp.SP;
import com.pj.utils.sg.AjaxError;
import com.pj.utils.sg.NbUtil;

import cn.dev33.satoken.sso.SaSsoUtil;

/**
 * Service: sys_user -- 用户表
 * 
 * @author kong
 * @since 2022-11-25
 */
@Service
@Slf4j
public class SysUserService {

	/** 底层 Mapper 对象 */
	@Autowired
	SysUserMapper sysUserMapper;

	/** 底层 Service 对象 */
	@Autowired
	SysUserPasswordService sysUserPasswordService;

	/** 底层 Service 对象 */
	@Autowired
	SysPointHistoryService sysPointHistoryService;

	/** 底层 Service 对象 */
	@Autowired
	SysClientMapper sysClientMapper;

	/** 底层 Service 对象 */
	@Autowired
	WxMpService wxMpService;

	@Autowired
	WxCardService wxCardService;

	@Autowired
	private ISysDictDataService dictDataService;

	/** 新增用户，返回新增的用户对象 */  
	@Transactional(rollbackFor = Exception.class)
	public SysUser add(SysUser s){
		// 如果没有提供手机号或邮箱，将其从空字符串设置为空 
		if(NbUtil.isNull(s.getPhone())) {
			s.setPhone(null);
		}
		if(NbUtil.isNull(s.getEmail())) {
			s.setEmail(null);
		}

		// 校验数据完整性 
		SysUserUtil.checkByAdd(s);
		
		// 写入数据库 
		sysUserMapper.add(s);

		// 查询
		SysUser s2;
		if(s.getId() == null || s.getId() == 0) {
			s2 = sysUserMapper.getById(SP.publicMapper.getPrimarykey());
		} else {
			s2 = sysUserMapper.getById(s.getId());
		}
		
		// 改密码
		sysUserPasswordService.updatePassword(s2.getId(), s.getPassword2());

		//  返回 
		return s2;
	}

	/** 删除用户 */  
	public void delete(long id){
		int line = SP.publicMapper.updateColumnById(SysUser.TABLE_NAME, "is_del", 2, id);
		AjaxError.notLine(line, "删除失败, 数据可能并不存在");
		// 单点注销这个账号 
		SaSsoUtil.ssoLogout(id);
	}

	/** 恢复用户 */  
	public void unDelete(long id){
		// 先校验一下各个属性，是否被占用 
		SysUser s = sysUserMapper.getById(id);
		AjaxError.notIsNull(s, "用户不存在");
		SysUserUtil.checkUsername(s);
		SysUserUtil.checkPhone(s);
		SysUserUtil.checkEmail(s);
		
		// 开始恢复 
		int line = SP.publicMapper.updateColumnById(SysUser.TABLE_NAME, "is_del", 1, id);
		AjaxError.notLine(line, "恢复失败, 数据可能并不存在");
	}

	/** 彻底删除用户 */  
	public void realDelete(long id){
		// 为保证数据安全性，物理删除前必须先逻辑删除 
		SysUser s = sysUserMapper.getById(id);
		AjaxError.notIsNull(s, "用户不存在");
		AjaxError.notTrue(s.getIsDel() == 1, "请先从用户列表中将此用户删除，然后再进行 [ 彻底删除 ] 操作");
		// 开始删除 
		int line = SP.publicMapper.deleteById(SysUser.TABLE_NAME, id);
		AjaxError.notLine(line, "彻底删除失败, 数据可能并不存在");
		// 单点注销这个账号 
		SaSsoUtil.ssoLogout(id);
	}

	/** 修改用户，返回修改的用户对象 */  
	@Transactional(rollbackFor = Exception.class)
	public SysUser update(SysUser s){
		// 数据校验 
		SysUserUtil.checkByUpdate(s);
		
		// 修改 
		int line = sysUserMapper.update(s);
		AjaxError.notLine(line, "修改失败, 数据可能并不存在");

		// 如果给禁用了，就停掉其 Token 有效果性，使其账号的登录状态立即无效 
		if(s.getStatus() == 2) {
			SaSsoUtil.ssoLogout(s.getId());
		}
		
		//  返回最新对象  
		return sysUserMapper.getById(s.getId());
	}


	/** 更新用户积分，返回修改的用户对象 */
	@Transactional(rollbackFor = Exception.class)
	public SaResult updatePoint(PointListenVO pointListenVO){

		//拿出这个用户的原始数据，进行计算
		String userPhone = pointListenVO.getPhone();
		SysUser byPhone = sysUserMapper.getByPhone(userPhone);
		log.info("用户的原始数据->"+byPhone.toString());

		if(byPhone.getTotalPoints()<pointListenVO.getVariablePoint()){	//用户积分不足则直接反馈提示结果
			SaResult.error("用户积分不足当前用户积分"+byPhone.getTotalPoints());
		}

		// 修改用户积分
		SysUser sysUser = new SysUser();
		sysUser.setId(byPhone.getId());
		log.info("原始积分："+byPhone.getTotalPoints()+"====》变动值："+pointListenVO.getVariablePoint());
		sysUser.setTotalPoints(byPhone.getTotalPoints()+pointListenVO.getVariablePoint());

		int line = sysUserMapper.updatePoint(sysUser);
		AjaxError.notLine(line, "修改失败, 数据可能并不存在");


		SysUser byId = sysUserMapper.getById(byPhone.getId());//获取更新后的用户
		log.info("更新后的用户信息->"+byId.toString());

		//增加积分变动记录
		SysPointHistory sysPointHistory = new SysPointHistory();
		sysPointHistory.setCreateBy(byId.getUsername());
		sysPointHistory.setUserId(byId.getId());
		sysPointHistory.setPhone(pointListenVO.getPhone());
		sysPointHistory.setPoint(byId.getTotalPoints());
		sysPointHistory.setBeforePoint(byPhone.getTotalPoints());
		sysPointHistory.setVariablePoint(pointListenVO.getVariablePoint());
		sysPointHistory.setPointType(pointListenVO.getPointType());
		sysPointHistory.setModuleType(pointListenVO.getModuleType());
		sysPointHistory.setPlatformId(pointListenVO.getPlatformType());
		sysPointHistory.setContent(pointListenVO.getContent());
		int add = sysPointHistoryService.add(sysPointHistory);



		//@TODO 目前只有一张卡，积分系统也只分一张卡的积分，所以按照openid查询卡信息，积分系统的积分 并没有区分client传过来的积分归属哪张卡
		QueryWrapper<WxCard> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("from_user",byId.getOpenid());
		WxCard one = wxCardService.getOne(queryWrapper);
		String dictLabel = dictDataService.selectDictLabel("points_type", pointListenVO.getPointType());
		//向微信推送积分变动
		WxMpMemberCardUpdateMessage wxMpMemberCardActivatedMessage = new WxMpMemberCardUpdateMessage();
		wxMpMemberCardActivatedMessage.setCode(one.getUserCardCode());   //卡券Code码
		wxMpMemberCardActivatedMessage.setCardId(one.getCardId());   //卡券ID
		wxMpMemberCardActivatedMessage.setAddBonus(pointListenVO.getVariablePoint());   //同步变动积分

		/*开发者可以同时传入add_bonus和bonus解决由于同步失败带来的幂等性问题。同时传入add_bonus和bonus时
		add_bonus作为积分变动消息中的变量值，而bonus作为卡面上的总积分额度显示。余额变动同理。 */
//		wxMpMemberCardActivatedMessage.setRecordBonus(byId.getTotalPoints().toString());

		wxMpMemberCardActivatedMessage.setRecordBonus(dictLabel);  //变动记录内容
		try {
			wxMpService.getMemberCardService().updateUserMemberCard(wxMpMemberCardActivatedMessage);
		}catch (Exception e){
			log.error(e.getMessage());
		}


		//  返回最新对象
		return SaResult.data(byId.getTotalPoints());
	}


	/** 会员卡内容更新事件回调 微信回调 */
	@Transactional(rollbackFor = Exception.class)
	public SaResult updateuser(WxMpXmlMessage wxMpXmlMessage){
		//根据code序列号查到该卡的用户信息
		SysUser byCardCode = sysUserMapper.getByCardCode(wxMpXmlMessage.getUserCardCode());
		log.info("用户的原始数据->"+byCardCode.toString());
		Integer modifyBonus = Integer.valueOf(wxMpXmlMessage.getModifyBonus());//变动的积分值转换
		if(byCardCode.getTotalPoints() < modifyBonus){	//用户积分不足则直接反馈提示结果
			SaResult.error("用户积分不足当前用户积分"+byCardCode.getTotalPoints());
		}

		// 修改用户积分
		SysUser sysUser = new SysUser();
		sysUser.setId(byCardCode.getId());
		sysUser.setTotalPoints(byCardCode.getTotalPoints()+modifyBonus);

		log.info("原始积分："+byCardCode.getTotalPoints()+"====》变动值："+modifyBonus);

		int line = sysUserMapper.updatePoint(sysUser);
		AjaxError.notLine(line, "修改失败, 数据可能并不存在");


		SysUser byId = sysUserMapper.getById(byCardCode.getId());//获取更新后的用户
		log.info("更新后的用户信息->"+byId.toString());

		//增加积分变动记录
		SysPointHistory sysPointHistory = new SysPointHistory();
		sysPointHistory.setCreateBy(byId.getUsername());
		sysPointHistory.setUserId(byId.getId());
		sysPointHistory.setPhone(byId.getPhone());
		sysPointHistory.setPoint(byId.getTotalPoints());
		sysPointHistory.setBeforePoint(byCardCode.getTotalPoints());
		sysPointHistory.setVariablePoint(modifyBonus);
		sysPointHistory.setPointType("CARD_CONSUME"); 	//@TODO 变动类型 暂定会员卡消耗
		sysPointHistory.setModuleType("MEMBER_CARD");	//@TODO 变动类型 暂定会员卡功能
		sysPointHistory.setPlatformId(999L);			//@TODO 平台来源 暂定999id为微信
		sysPointHistory.setContent("微信使用");			//@TODO 平台来源 暂定为微信使用
		int add = sysPointHistoryService.add(sysPointHistory);


		//  返回最新对象
		return SaResult.data(byId.getTotalPoints());
	}

}
